#!/usr/bin/perl
#
use strict;
use warnings;

use lib '/home/netdisco/perl5/lib/perl5';
use App::Netdisco;
use Dancer ':script';
use Dancer::Plugin::DBIC 'schema';

use Data::Printer;
use App::Netdisco::Util::Device ':all';
use App::Netdisco::Util::Permission ':all';
use App::Netdisco::Util::Web;	# for sort_port

my $use_files = 1;

use Data::Dumper;

my $domain_suffix = setting( 'domain_suffix' );
my $settings = setting( 'ndt' );
my $dev_regexp = $settings->{ 'dev_regexp' } || 'sw-.*';
my $ap_regexp = $settings->{ 'ap_regexp' } || 'ap.*';
my $down_age = $settings->{ 'down_age' } || '1 hour';
my $remote_override = $settings->{ 'remote_override' } || {};
my $roots = $settings->{ 'roots' };
my $onpath_cfg = $settings->{ 'onpath_cfg' };
my $offpath_cfg = $settings->{ 'offpath_cfg' };
my $ap_cfg = $settings->{ 'ap_cfg' };

if (!$roots || !$onpath_cfg || !$offpath_cfg) {
   die "Make sure to set roots, onpath_cfg and offpath_cfg!!\n";
}

# We need all of the ports on all of the devices that match
# the regexp.
my @devices = schema('netdisco')->resultset('Device')->search({},
  {
    '+columns' => {
      old => \"age(now(), last_discover) > interval '$down_age'"
    }
  })->all;

my %porttype = ();
my %remote = ();
foreach my $device (@devices) {
	my $name = lc($device->name);
	$name =~ s/$domain_suffix//;
	if ($name =~ $dev_regexp) {
		$porttype{ $name } = {};
		my @ports = schema('netdisco')->resultset('DevicePort')->search({ip => $device->ip});
		foreach my $port (@ports) {
			my $port_name = $port->port;
			if ($port_name =~ /Ethernet/) {
				$porttype{ $name }{ $port_name } = 'unknown';
				my $remote_id;
				if (exists($remote_override->{ $name }{ $port_name })) {
					$remote_id = $remote_override->{ $name }{ $port_name };
				} elsif ($port->neighbor) {
					$remote_id = $port->neighbor->name;
				} else {
					$remote_id = $port->remote_id;
				}
				if ($remote_id) {
					$remote_id =~ s/$domain_suffix//;
					$remote{ $name }{ $port_name } = $remote_id;
				}
			}
		}
	}
}

my %rungraph = ();
foreach my $root (@$roots) {
	print $root, "\n";
	my ($dev, $port, $who) = split(/:/, $root);
	$porttype{ $dev }{ $port } = $who;
	if ($rungraph{ $dev }) {
		next;
	}
	$rungraph{ $dev } = 1;

	# Find the graphviz node name for $dev.
	my $gvnode = qx/gvpr 'N [ \$.label == "$dev" ] { printf( "%s\n", \$.name ) }' graph_raw.dot/;
	chomp $gvnode;

	if ($gvnode eq '') {
		print "Can't find node in graph_raw.dot for $dev\n";
		exit(-1);
	}
	print "$dev -> $gvnode\n";
	my $cmd = q/dijkstra -p / . $gvnode . q/ graph_raw.dot | gvpr 'N [ $.dist != "0.000" ] { node_t n; n = node( $G, $.prev ); printf( "%s %s\n", $.label, n.label ) }' |/;
	open( NODES, $cmd );
	while (<NODES>) {
		chomp;
		my ( $downlink, $uplink ) = split;
		foreach my $port ( keys( %{$remote{ $downlink }} ) ) {
			if (lc( $remote{ $downlink }{ $port } ) eq $uplink ) {
				$porttype{ $downlink }{ $port } = "uplink to $uplink for $who";
			}
		}
	}
}

#print Dumper( \%porttype );
#print Dumper( \%remote );
foreach my $device (sort keys( %porttype )) {
	if ($use_files) {
		open( CFG, ">${device}.cfg" );
		print CFG "conf t\n";
	} else {
		*CFG = *STDOUT;
		print "\n\n$device configuration:\n!\n";
	}
	foreach my $port (sort { &App::Netdisco::Util::Web::sort_port( $a, $b ) } keys( %{$porttype{ $device }} )) {
		print CFG "interface $port\n";
		if ( $remote{ $device }{ $port } ) {
			print CFG "   description $remote{ $device }{ $port }\n";
		}
		my $cfg;
		if ($porttype{ $device }{ $port } ne 'unknown') {
			print CFG "   ! $porttype{ $device }{ $port }\n";
			$cfg = $onpath_cfg;
		} else {
			$cfg = $offpath_cfg;
		}
		foreach my $line (@$cfg) {
			print CFG "   $line\n";
		}
		if ( defined( $remote{ $device }{ $port } ) &&
				$remote{ $device }{ $port } =~ $ap_regexp ) {
			foreach my $line (@$ap_cfg) {
				print CFG "   $line\n";
			}
		}
	}
	print CFG "end\nwr\n";
}
